package com.rent.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rent.common.enums.UserRole;
import com.rent.common.exception.BusinessException;
import com.rent.common.interceptor.UserContext;
import com.rent.common.service.StorageService;
import com.rent.common.util.JwtUtil;
import com.rent.common.util.MD5Util;
import com.rent.common.util.RedisUtil;
import com.rent.user.mapper.UserMapper;
import com.rent.user.pojo.dto.*;
import com.rent.user.pojo.entity.User;
import com.rent.common.entity.UserVo;
import com.rent.user.pojo.vo.UserBaseInfoVo;
import com.rent.user.service.UserService;
import com.rent.user.util.CodeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 用户服务实现类
 * 
 * 实现UserService接口的所有方法
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private CodeUtil codeUtil;

    @Autowired
    private StorageService storageService;

//    @Autowired
//    private JwtUtil jwtUtil;

    // 短信验证码相关常量
    private static final String SMS_CODE_PREFIX = "sms:code:";
    private static final long SMS_CODE_EXPIRE = 300L; // 5分钟
    private static final String DEFAULT_PASSWORD = "123456"; // 默认密码

    // 用户注册
    @Override
    public void  register(RegisterDto registerDto) {
        log.info("用户注册尝试：username={}", registerDto.getUsername());

        // 1.验证短信验证码
        if (!codeUtil.verifySmsCode(registerDto.getPhone(), registerDto.getCode())) {
            throw new BusinessException("验证码错误或已过期");
        }

        QueryWrapper<User> usernameQuery = new QueryWrapper<>();

        // 2.检查用户名是否已存在
        usernameQuery.eq("username", registerDto.getUsername());
        if (this.getOne(usernameQuery) != null) {
            log.info("用户名已存在：username={}", registerDto.getUsername());
            throw new BusinessException("用户名已存在");
        }

        // 3.检查手机号是否已存在
        QueryWrapper<User> phoneQuery = new QueryWrapper<>();
        phoneQuery.eq("phone", registerDto.getPhone());
        if (this.getOne(phoneQuery) != null) {
            log.info("手机号已存在：phone={}", registerDto.getPhone());
            throw new BusinessException("手机号已被注册");
        }

        // 4.检查邮箱是否已存在
        QueryWrapper<User> emailQuery = new QueryWrapper<>();
        emailQuery.eq("email", registerDto.getEmail());
        if (this.getOne(emailQuery) != null) {
            log.info("邮箱已存在：email={}", registerDto.getEmail());
            throw new BusinessException("邮箱已被注册");
        }

        // 5.创建用户实体
        User user = new User();
        BeanUtils.copyProperties(registerDto, user);

        // 6.密码加密
        user.setPassword(MD5Util.encrypt(registerDto.getPassword()));

        // 7.设置默认值（用户默认为角色为租客）
        user.setRole(registerDto.getRole() != null ? registerDto.getRole() : UserRole.TENANT.getCode());
        user.setStatus(0); // 正常状态
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());

        // 8.保存用户
        if (!this.save(user)) {
            throw new BusinessException("注册失败，请稍后重试");
        }

        log.info("用户注册成功：username={}, userId={}", user.getUsername(), user.getId());
    }

    // 用户登录
    @Override
    public Map<String, Object> login(LoginDto loginDto) {
        log.info("用户登录尝试: username={}", loginDto.getUsername());
        // 1.根据用户名查询用户
        User user = this.getOne(new QueryWrapper<User>().eq("username", loginDto.getUsername()));
        log.info("用户查询结果：user={}", user);
        if (user == null) {
            log.info("用户不存在：username={}", loginDto.getUsername());
            throw new BusinessException("用户名或密码错误");
        }

        // 2.验证密码
        if (!MD5Util.verify(loginDto.getPassword(), user.getPassword())) {
            log.info("密码错误：username={}", loginDto.getUsername());
            throw new BusinessException("用户名或密码错误");
        }

        // 3.检查用户状态
        if (user.getStatus() != null && user.getStatus() == 1) {
            log.info("账号已被禁用：username={}", loginDto.getUsername());
            throw new BusinessException("账号已被禁用，请联系管理员");
        }

        // 4.生成JWT Token
        String token = JwtUtil.generateToken(user.getId(), user.getUsername(), user.getRole());
        if (token == null) {
            log.info("JWT Token生成失败：username={}", loginDto.getUsername());
            throw new BusinessException("登录失败，请稍后重试");
        }

        // 5.单点登录处理(清除旧token，缓存新token)
        SingleSignOn(user.getId(), token, user);

        // 6.更新最后登录时间
        user.setUpdateTime(new Date());
        this.updateById(user);

        // 7.构建返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("token", token);

        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("id", user.getId());
        userInfo.put("username", user.getUsername());
        userInfo.put("phone", user.getPhone());
        userInfo.put("email", user.getEmail());
        userInfo.put("realName", user.getRealName());
        userInfo.put("role", user.getRole());
        userInfo.put("avatar", user.getAvatar());
        result.put("user", userInfo);

        log.info("用户登录成功: username={}, userId={}", user.getUsername(), user.getId());
        return result;
    }

    // 更新用户信息
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateUser(User user) {
        // 更新时间
        user.setUpdateTime(new Date());
        boolean success = this.updateById(user);
        if (success) {
            // 更新缓存中的用户信息
            String token = (String) redisUtil.get("user:id:" + user.getId());
            if (token != null) {
                redisUtil.set("user:token:" + token, user, 604800L);
            }
        }
        return success;
    }

    // 一键登录
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> smsLogin(SmsLoginDto smsLoginDto) {
        log.info("用户一键登录尝试: phone={}", smsLoginDto.getPhone());

        // 1.验证短信验证码
        if (!codeUtil.verifySmsCode(smsLoginDto.getPhone(), smsLoginDto.getCode())) {
            throw new BusinessException("验证码错误或已过期");
        }

        // 2.根据手机号查询用户
        User user = this.getOne(new QueryWrapper<User>().eq("phone", smsLoginDto.getPhone()));

        // 3.如果用户不存在，自动注册
        if (user == null) {
            // 生成默认用户名（手机号+随机后缀）
            String username = "user_" + smsLoginDto.getPhone() + "_" + System.currentTimeMillis() % 10000;

            user = new User();
            user.setUsername(username);
            user.setPhone(smsLoginDto.getPhone());
            user.setPassword(MD5Util.encrypt(DEFAULT_PASSWORD)); // 设置默认密码
            user.setRole(UserRole.TENANT.getCode()); // 默认角色为租客
            user.setStatus(0); // 正常状态
            user.setCreateTime(new Date());
            user.setUpdateTime(new Date());

            if (!this.save(user)) {
                throw new BusinessException("自动注册失败，请稍后重试");
            }

            log.info("自动注册新用户: phone={}, userId={}", smsLoginDto.getPhone(), user.getId());
        }

        // 4.检查用户状态
        if (user.getStatus() != null && user.getStatus() == 1) {
            log.info("账号已被禁用：phone={}", smsLoginDto.getPhone());
            throw new BusinessException("账号已被禁用，请联系管理员");
        }

        // 5.生成JWT Token
        String token = JwtUtil.generateToken(user.getId(), user.getUsername(), user.getRole());
        if (token == null) {
            log.info("JWT Token生成失败：phone={}", smsLoginDto.getPhone());
            throw new BusinessException("登录失败，请稍后重试");
        }

        // 6.单点登录处理(清除旧token，缓存新token)
        SingleSignOn(user.getId(), token, user);

        // 7.更新最后登录时间
        user.setUpdateTime(new Date());
        this.updateById(user);

        // 8.清除已使用的验证码
        redisUtil.delete(SMS_CODE_PREFIX + smsLoginDto.getPhone());

        // 9.构建返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("token", token);

        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("id", user.getId());
        userInfo.put("username", user.getUsername());
        userInfo.put("phone", user.getPhone());
        userInfo.put("email", user.getEmail());
        userInfo.put("realName", user.getRealName());
        userInfo.put("role", user.getRole());
        userInfo.put("avatar", user.getAvatar());
        result.put("user", userInfo);

        log.info("用户一键登录成功: phone={}, userId={}", smsLoginDto.getPhone(), user.getId());
        return result;
    }

    // 发送短信验证码
    @Override
    public boolean sendSmsCode(String phone) {
        try {
            // 1.生成6位随机验证码
            String code = codeUtil.generateRandomCode(6);

            // 2.存储验证码到Redis，5分钟过期
            String redisKey = SMS_CODE_PREFIX + phone;
            redisUtil.set(redisKey, code, SMS_CODE_EXPIRE);

            // 3.发送验证码
            boolean sendResult = codeUtil.sendCode(phone, code);

            if (sendResult) {
                log.info("短信验证码发送成功: phone={}, code={}", phone, code);
                return true;
            } else {
                log.error("短信验证码发送失败: phone={}", phone);
                // 发送失败时清除Redis中的验证码
                redisUtil.delete(redisKey);
                return false;
            }
        } catch (Exception e) {
            log.error("发送短信验证码异常: phone={}", phone, e);
            return false;
        }
    }

    // 修改密码
    @Override
    public boolean  updatePassword(UpdatePasswordDto updatePasswordDto) {
        log.info("用户修改密码尝试");

        // 1.从UserContext获取当前用户信息
        Long userId = UserContext.getUserId();
        if (userId == null) {
            log.info("用户未登录！");
            throw new BusinessException("用户未登录，请重新登录！");
        }

        // 2.校验两次密码
        if (!updatePasswordDto.getNewPassword().equals(updatePasswordDto.getConfirmPassword())) {
            log.info("两次密码不一致！: userId={}", userId);
            throw new BusinessException("两次密码不一致！");
        }

        // 3.查询最新的用户信息
        User user = this.getById(userId);
        if (user == null) {
            log.info("用户不存在: userId={}", userId);
            throw new BusinessException("用户不存在");
        }

        // 4.验证旧密码
        if (!MD5Util.verify(updatePasswordDto.getOldPassword(), user.getPassword())) {
            log.info("旧密码错误: userId={}", userId);
            throw new BusinessException("旧密码错误");
        }
        // 新密码不能与旧密码相同
        if (MD5Util.verify(updatePasswordDto.getNewPassword(), user.getPassword())) {
            log.info("新密码不能与旧密码相同: userId={}", userId);
            throw new BusinessException("新密码不能与旧密码相同");
        }

        // 5.加密新密码并更新
        String encryptedNewPassword = MD5Util.encrypt(updatePasswordDto.getNewPassword());
        user.setPassword(encryptedNewPassword);
        user.setUpdateTime(new Date());

        boolean success = this.updateById(user);

        if (success) {
            // 6.清除用户相关的token，重新登录
            String tokenKey = "user:id:" + userId;
            String token = (String) redisUtil.get(tokenKey);
            if (token != null) {
                redisUtil.delete("user:token:" + token);
                redisUtil.delete("user:id:" + userId);
                redisUtil.delete(tokenKey);
            }

            log.info("密码修改成功: userId={}, username={}", userId, user.getUsername());
        } else {
            log.error("密码修改失败: userId={}", userId);
        }
        return success;
    }

    // 上传头像
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String uploadAvatar(MultipartFile file) {
        log.info("用户上传头像尝试");

        // 1.获取用户状态
        Long userId = UserContext.getUserId();
        if (userId == null) {
            log.info("用户未登录！");
            throw new BusinessException("用户未登录，请重新登录！");
        }

        User user = new User();
        // 2.如果存在旧头像文件则删除旧头像文件
        if (StringUtils.hasText(user.getAvatar())) {
            try {
                storageService.delete(user.getAvatar());
            } catch (IOException e) {
                log.warn("删除旧头像文件失败: {}", user.getAvatar(), e);
            }
        }

        // 3.上传头像文件
        String avatarUrl;
        try {
            avatarUrl = storageService.upload("avatar", file);
        } catch (IOException e) {
            log.error("头像文件上传失败: userId={}", userId, e);
            throw new BusinessException("文件上传失败");
        }

        // 4.更新用户头像并保存
        user.setId(userId);
        user.setAvatar(avatarUrl);
        this.updateById(user);

        // 5.更新缓存中的用户信息
        String tokenKey = "user:id:" + user.getId();
        String token = (String) redisUtil.get(tokenKey);
        if (token != null) {
            redisUtil.set("user:token:" + token, user, 604800L);
        }

        // 6.返回结果
        log.info("用户上传头像成功: userId={}, username={}", userId, UserContext.getUsername());
        return avatarUrl;
    }

    // 获取用户统计信息
    @Override
    public UserBaseInfoVo getBaseInfo(Long userId) {
        log.info("获取用户统计信息: userId={}", userId);

        // 验证用户是否登录
        if (userId == null) {
            log.error("获取统计信息失败：用户ID为空");
            throw new BusinessException("用户未登录，请先登录");
        }

        // 验证用户是否存在
        User user = this.getById(userId);
        if (user == null) {
            log.error("获取统计信息失败：用户不存在，userId={}", userId);
            throw new BusinessException("用户不存在");
        }

        // 检查用户状态
        if (user.getStatus() != null && user.getStatus() == 1) {
            log.error("获取统计信息失败：账号已被禁用，userId={}", userId);
            throw new BusinessException("账号已被禁用，请联系管理员");
        }

        // 调用Mapper获取统计信息
        UserBaseInfoVo baseInfo = baseMapper.getUserBaseInfo(userId);

        // 如果查询结果为空，创建默认对象并设置基础用户信息
        if (baseInfo == null) {
            throw new BusinessException("用户统计信息为空");
        }

        log.info("用户统计信息获取成功: userId={}, username={}", userId, user.getUsername());
        return baseInfo;
    }

    @Transactional
    @Override
    public boolean updateUserRole(Long userId, Integer roleId) {
        User user = this.getById(userId);
        user.setRole(roleId);
        return this.updateById(user);
    }

    // 单点登录
    private void SingleSignOn(Long userId, String token, User user) {
        String userIdKey = "user:id:" + userId;
        String oldToken = (String) redisUtil.get(userIdKey);

        // 清除旧的登录状态
        if (oldToken != null) {
            redisUtil.delete("user:token:" + oldToken); // 删除旧的token缓存
            redisUtil.delete(userIdKey); // 删除旧的userId映射
            log.info("清除用户旧登录状态: userId={}, oldToken={}", userId, oldToken);
        }

        // 转换为UserVo再缓存
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user,userVo);

        // 缓存UserVo对象而不是User对象
        redisUtil.set("user:token:" + token, userVo, 604800L);
        redisUtil.set(userIdKey, token, 604800L);

        log.info("单点登录处理完成: userId={}, token={}", userId, token);
    }

    // 用户统计信息
}